package org.example.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.contrib.javanica.conf.HystrixPropertiesManager;
import lombok.extern.slf4j.Slf4j;
import org.example.feign.client.UserClient;
import org.example.pojo.Order;
import org.example.pojo.Product;
import org.example.pojo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService{

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserClient userClient;

    //单个查询的业务方法，配置hystrix，一定阈值则合并调用batch方法
    @HystrixCollapser(batchMethod = "getOrderInfoList"
            ,scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL
            ,collapserProperties = {
            @HystrixProperty(name = "timerDelayInMilliseconds",value = "200"),
            //batch size
            @HystrixProperty(name = "maxRequestsInBatch",value = "200")
    })
    @Override
    public Future<Order> getFutureOrderInfo(Integer orderNo) {
        log.info("query one order by id");
        return null;
    }

    //需要调用的batch方法
    @HystrixCommand
    @Override
    public List<Order> getOrderInfoList(List<Integer> orderNos) {
        log.info("query ordesr by batch");
        List<Order> orders=new ArrayList<>();
        for(Integer orderNo:orderNos){
            Order order=new Order();
            order.setId(orderNo);
            order.setSkuName("订单"+orderNo+"的sku");
            order.setUserInfo(new UserVo());
            order.getUserInfo().setUserId(orderNo+2244);
            orders.add(order);
        }
        return orders;
    }


    @HystrixCommand(groupKey = "listPool"
            ,commandKey = "getProductList"
            ,threadPoolKey = "listPool"
            ,commandProperties = {
                  @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")
//            ,信号量隔离，信号量隔离时，相当于同步竞争锁，先到先得，没了等着
//            @HystrixProperty(name= HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE")
             }
            ,threadPoolProperties = {
            //线程池大小
            @HystrixProperty(name = "coreSize",value = "5"),
            //队列等待阈值，最大队列长度，默认-1
            @HystrixProperty(name = "maxQueueSize",value = "100"),
            //线程存活时间，默认一分钟
            @HystrixProperty(name = "keepAliveTimeMinutes",value = "2"),
            //超出队列等待阈值的拒绝策略
            @HystrixProperty(name = "queueSizeRejectionThreshold",value = "100"),
    }
    //降级处理
//    ,fallbackMethod =""
    )
    @Override
//    @Cacheable(cacheNames = {"getProductList"})
    public List<Product> getProductList(){
        log.info("{}",Thread.currentThread().getName());
        return  userClient.getList();
    }

    @HystrixCommand(groupKey = "singlePool"
            ,commandKey = "getOrderInfo"
            ,threadPoolKey = "singlePool"
            ,commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000")
    }
            ,threadPoolProperties = {
            //线程池大小
            @HystrixProperty(name = "coreSize",value = "2"),
            //队列等待阈值，最大队列长度，默认-1
            @HystrixProperty(name = "maxQueueSize",value = "100"),
            //线程存活时间，默认一分钟
            @HystrixProperty(name = "keepAliveTimeMinutes",value = "2"),
            //超出队列等待阈值的拒绝策略
            @HystrixProperty(name = "queueSizeRejectionThreshold",value = "100"),
    })
    @Override
//    @Cacheable(cacheNames = {"byId"},key = "#orderNo")
    public Order getOrderInfo(Integer orderNo) {
        log.info("{}",Thread.currentThread().getName());
        Order order = new Order();
        order.setId(orderNo);
        order.setSkuId(2203);
        order.setSkuName("商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀");
        order.setUserInfo(getUserInfoByIdWithFeign(110));
        return order;

    }
    @Override
//    @Cacheable(cacheNames = {"byId"},key = "#orderNo")
    public Order getOrderInfo2(Integer orderNo) {
        log.info("{}",Thread.currentThread().getName());
        Order order = new Order();
        order.setId(orderNo);
        order.setSkuId(2203);
        order.setSkuName("商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀商品-无敌双刀");
        order.setUserInfo(getUserInfoByIdWithFeign(110));
        return order;

    }

    private UserVo getUserInfoByIdWithFeign(Integer i) {
        UserVo user=userClient.getUser(i);
        return user;
    }

    private UserVo getUserInfoById(Integer i) {
        ResponseEntity<UserVo> entity=restTemplate
                .exchange("http://service-provider/api/user?userId=" + i
                , HttpMethod.GET
                , null
                , new ParameterizedTypeReference<UserVo>() {

                });
        UserVo user=entity.getBody();
        return user;
    }
}
